package com.shycloud.mido.organ.controller;

import java.io.IOException;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.domain.AlipayTradePrecreateModel;
import com.alipay.api.domain.AlipayTradeQueryModel;
import com.alipay.api.request.AlipayTradePrecreateRequest;
import com.alipay.api.request.AlipayTradeQueryRequest;
import com.alipay.api.response.AlipayTradePrecreateResponse;
import com.alipay.api.response.AlipayTradeQueryResponse;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.shycloud.mido.common.core.exception.BusinessException;
import com.shycloud.mido.common.core.util.R;
import com.shycloud.mido.common.pay.alipay.AlipayConfig;
import com.shycloud.mido.common.pay.alipay.bean.AliReturnPayBean;
import com.shycloud.mido.common.pay.alipay.bean.OrderBean;
import com.shycloud.mido.common.pay.alipay.utils.AliH5PayUtil;
import com.shycloud.mido.common.pay.wxpay.WXPay;
import com.shycloud.mido.common.pay.wxpay.utils.PayCommonUtil;
import com.shycloud.mido.common.pay.wxpay.utils.WxConfigUtil;
import com.shycloud.mido.organ.api.entity.H5PayOrder;
import com.shycloud.mido.organ.api.entity.OnlineCourseGoodsEntity;
import com.shycloud.mido.organ.api.entity.Organization;
import com.shycloud.mido.organ.mapper.H5PayOrderMapper;
import com.shycloud.mido.organ.mapper.OnlineCourseGoodsMapper;
import com.shycloud.mido.organ.mapper.OrganizationMapper;

import org.jdom.JDOMException;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import lombok.AllArgsConstructor;

@RestController
@AllArgsConstructor
@RequestMapping("/onlineBuy")
public class OnlineCourseBuyController {
    //回调地址常量
    private final static String WX_NOTIFY_URL = "http://api.joymido.com/organization/onlineBuy/wxNotify";
    private final static String ALI_NOTIFY_URL = "http://api.joymido.com/organization/onlineBuy/aliNotify";
    private final static String WX_NOTIFY_URL_TEST = "http://a99zg89a.xiaomy.net/organization/onlineBuy/wxNotify";
    private final static String ALI_NOTIFY_URL_TEST = "http://a99zg89a.xiaomy.net/organization/onlineBuy/aliNotify";
    private final static String RETURN_URL = "http://buyclasshours.joymido.com/";
    private final static String ORDER_BODY = "快乐斑马-课时购买";
    private static AlipayConfig config = new AlipayConfig();

    private OrganizationMapper organMapper;
    private OnlineCourseGoodsMapper goodsMapper;
    private H5PayOrderMapper orderMapper;

    //返回机构剩余课程时长(单位为分钟)
    @GetMapping("/getOnlineCourseSurplus")
    public R getOnlineCourseSurplus(String orgId){
        Organization org = organMapper.selectById(orgId);
        return new R<>(org.getOnlineCourseAvail());
    }

    @GetMapping("/getGoodsList")
    public R getGoodsList(){
        QueryWrapper queryWrapper = new QueryWrapper<>();
        return new R<>(goodsMapper.selectList(queryWrapper));
    }

    @GetMapping("/getOpenId")
    public R getOpenId(String code) {
        String requestUrl = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=wxc2c56539545182cb&secret=d663753e2ecf6c056d69228d2b99c651&grant_type=authorization_code&code=";
        requestUrl = requestUrl+code;
        JSONObject json = PayCommonUtil.httpsRequest(requestUrl, "POST");
        return new R<>(json);
    }

    //微信JSAPI下单
    @GetMapping("/wxCreateOrderJSAPI")
    public R wxCreateOrderJSAPI(String memberId, String openId, Integer orgId, Integer goodsId){
        OnlineCourseGoodsEntity goods = goodsMapper.selectById(goodsId);
        //生成订单
        H5PayOrder order = new H5PayOrder();
        order.setMemberId(memberId);
        order.setOrgId(orgId);
        order.setPayMethod("微信JSAPI");
        order.setAmount(goods.getPrice());
        //购买的时长+赠送的时长为实际账号获得时长
        order.setDuration(goods.getBuyDuration() + goods.getGiveDuration());
        orderMapper.insert(order);
        //调用微信统一下单接口
        SortedMap<Object, Object> parameters = new TreeMap<>();
        parameters.put("mch_id", WxConfigUtil.MCH_ID);
        parameters.put("appid", WxConfigUtil.APPIDH5);
        parameters.put("nonce_str", PayCommonUtil.createNoncestr());
        parameters.put("body", ORDER_BODY);
        parameters.put("out_trade_no", order.getId());
        //微信支付以分为单位
        int fen = (int)(goods.getPrice()*100);
        String totalFee = String.valueOf(fen);
        parameters.put("total_fee", totalFee);
        parameters.put("spbill_create_ip", PayCommonUtil.getIPAddress());
        parameters.put("notify_url", WX_NOTIFY_URL);
        parameters.put("sign_type", "MD5");
        parameters.put("trade_type", "JSAPI");
        parameters.put("openid", openId);
        //此处进行二次加签, 帮助前端进行签名操作
        Map<String, String> result = PayCommonUtil.wxRequest(WxConfigUtil.UNIFIED_ORDER_URL, "POST", WxConfigUtil.MD5, parameters);
        SortedMap<Object, Object> parameters2 = new TreeMap<>();
        parameters2.put("appId", WxConfigUtil.APPIDH5);
        parameters2.put("nonceStr", result.get("nonce_str"));
        parameters2.put("package", "prepay_id="+result.get("prepay_id"));
        parameters2.put("signType", "MD5");
        Long s = System.currentTimeMillis() / 1000;
        String timeStamp = String.valueOf(s);
        parameters2.put("timeStamp", timeStamp);
        String sign = PayCommonUtil.commonSignCreate(parameters2, "UTF-8", WxConfigUtil.API_KEY, WxConfigUtil.MD5);
        parameters2.put("paySign", sign);
        parameters2.put("orderId", order.getId());
        return new R<>(parameters2);
    }

    //微信H5统一下单
    @GetMapping("/wxCreateOrderH5")
    public R wxCreateOrderH5(String memberId, Integer orgId, Integer goodsId) {
        OnlineCourseGoodsEntity goods = goodsMapper.selectById(goodsId);
        //生成订单
        H5PayOrder order = new H5PayOrder();
        order.setMemberId(memberId);
        order.setOrgId(orgId);
        order.setPayMethod("微信H5");
        order.setAmount(goods.getPrice());
        //购买的时长+赠送的时长为实际账号获得时长
        order.setDuration(goods.getBuyDuration() + goods.getGiveDuration());
        orderMapper.insert(order);

        SortedMap<Object, Object> parameters = new TreeMap<>();
        parameters.put("mch_id", WxConfigUtil.MCH_ID);
        parameters.put("appid", WxConfigUtil.APPID);
        parameters.put("nonce_str", PayCommonUtil.createNoncestr());
        parameters.put("body", ORDER_BODY);
        parameters.put("out_trade_no", order.getId());
        int fen = (int)(goods.getPrice()*100);
        String totalFee = String.valueOf(fen);
        parameters.put("total_fee", totalFee);
        parameters.put("spbill_create_ip", PayCommonUtil.getIPAddress());
        parameters.put("notify_url", WX_NOTIFY_URL);
        parameters.put("trade_type", "MWEB");
        //场景信息
        Map<String, Object> sceneMap = new LinkedHashMap<String, Object>();
        Map<String, Object> h5Info = new LinkedHashMap<String, Object>();
        h5Info.put("type", "Wap");
        h5Info.put("wap_url", "http://buyclasshours.joymido.com/");
        h5Info.put("wap_name","扫码支付");
        sceneMap.put("h5_info", h5Info);
        parameters.put("scene_info", JSON.toJSONString(sceneMap));
        Map<String, String> map = PayCommonUtil.wxRequest(WxConfigUtil.UNIFIED_ORDER_URL, "POST", WxConfigUtil.MD5, parameters);
        map.put("orderId", order.getId());
        map.put("mweb_url", map.get("mweb_url")+"&redirect_url=http%3A%2F%2F"+"buyclasshours.joymido.com/?flag=wx@" + order.getId()+"@");
        return new R<>(map);
    }

    //微信扫码支付
    @GetMapping("/wxCreateOrderNative")
    public R wxCreateOrderNative(Integer orgId, Integer goodsId){
        OnlineCourseGoodsEntity goods = goodsMapper.selectById(goodsId);
        //生成订单
        H5PayOrder order = new H5PayOrder();
        //后台订单没有memberId
        order.setOrgId(orgId);
        order.setPayMethod("微信扫码");
        order.setAmount(goods.getPrice());
        //购买的时长+赠送的时长为实际账号获得时长
        order.setDuration(goods.getBuyDuration() + goods.getGiveDuration());
        orderMapper.insert(order);

        SortedMap<Object, Object> parameters = new TreeMap<>();
        parameters.put("mch_id", WxConfigUtil.MCH_IDH5);
        parameters.put("appid", WxConfigUtil.APPIDH5);
        parameters.put("nonce_str", PayCommonUtil.createNoncestr());
        parameters.put("body", ORDER_BODY);
        parameters.put("out_trade_no", order.getId());
        int fen = (int)(goods.getPrice()*100);
        String totalFee = String.valueOf(fen);
        parameters.put("total_fee", totalFee);
        parameters.put("spbill_create_ip", PayCommonUtil.getIPAddress());
        parameters.put("notify_url", WX_NOTIFY_URL);
        parameters.put("trade_type", "NATIVE");
        parameters.put("product_id", order.getId());
        Map<String, String> map = PayCommonUtil.wxH5Request(WxConfigUtil.UNIFIED_ORDER_URL, "POST", WxConfigUtil.MD5, parameters);
        map.put("orderId", order.getId());
        return new R<>(map);
    }

    @GetMapping("/wxQueryOrder")
    public R wxQueryOrder(String orderId){
        SortedMap<Object, Object> parameters = new TreeMap<>();
        parameters.put("mch_id", WxConfigUtil.MCH_ID);
        parameters.put("appid", WxConfigUtil.APPID);
        parameters.put("nonce_str", PayCommonUtil.createNoncestr());
        parameters.put("out_trade_no", orderId);
        parameters.put("sign_type", "MD5");
        Map<String, String> map = PayCommonUtil.wxRequest(WxConfigUtil.ORDER_QUERY, "POST", WxConfigUtil.MD5, parameters);
        if(map.get("result_code").equals("SUCCESS")){
            if(map.get("trade_state").equals("SUCCESS")){
                return new R<>(true);
            }else{
                return new R<>(false);
            }
        }
        else{
            return new R<>(false);
        }
    }

    //微信后台查询订单信息(扫码支付时appId不一致)
    @GetMapping("/wxQueryOrderAdmin")
    public R wxQueryOrderAdmin(String orderId){
        SortedMap<Object, Object> parameters = new TreeMap<>();
        parameters.put("mch_id", WxConfigUtil.MCH_IDH5);
        parameters.put("appid", WxConfigUtil.APPIDH5);
        parameters.put("nonce_str", PayCommonUtil.createNoncestr());
        parameters.put("out_trade_no", orderId);
        parameters.put("sign_type", "MD5");
        Map<String, String> map = PayCommonUtil.wxH5Request(WxConfigUtil.ORDER_QUERY, "POST", WxConfigUtil.MD5, parameters);
        if(map.get("result_code").equals("SUCCESS")){
            if(map.get("trade_state").equals("SUCCESS")){
                return new R<>(true);
            }else{
                return new R<>(false);
            }
        }
        else{
            return new R<>(false);
        }
    }

    @PostMapping("/wxNotify")
    @Transactional(rollbackFor = Exception.class)
    public R wxNotify(HttpServletRequest request, HttpServletResponse response){
        Map<String, String> map = new HashMap<>();
        try{
            map = WXPay.wxNotify(request, response);
            H5PayOrder order = orderMapper.selectById(map.get("out_trade_no"));
            if(order.getStatus() == 0){
                order.setStatus(1);
                orderMapper.updateById(order);
                //更新在线课的课时
                Organization org = organMapper.selectById(order.getOrgId());
                //机构剩余课时数量为:原有数量+本次购买获取数量
                org.setOnlineCourseAvail(org.getOnlineCourseAvail() + order.getDuration());
                organMapper.updateById(org);
            }
        } catch (IOException e) {
            e.printStackTrace();
            throw new BusinessException("微信支付回调处理异常！");
        } catch (JDOMException e) {
            e.printStackTrace();
            throw new BusinessException("微信支付回调处理异常！");
        }
        return new R<>(map);
    }

    //支付宝H5支付
    @GetMapping("/aliCreateOrderH5")
    public R aliCreateOrderH5(String memberId, Integer orgId, Integer goodsId){
        OnlineCourseGoodsEntity goods = goodsMapper.selectById(goodsId);
        //生成订单
        H5PayOrder order = new H5PayOrder();
        order.setMemberId(memberId);
        order.setOrgId(orgId);
        order.setPayMethod("支付宝H5");
        order.setAmount(goods.getPrice());
        //购买的时长+赠送的时长为实际账号获得时长
        order.setDuration(goods.getBuyDuration() + goods.getGiveDuration());
        orderMapper.insert(order);

        OrderBean orderBean = new OrderBean();
        orderBean.setBody(ORDER_BODY);
        orderBean.setTotalAmount(order.getAmount().toString());
        orderBean.setOutTradeNo(order.getId());
        orderBean.setNotifyUrl(ALI_NOTIFY_URL);
        orderBean.setReturnUrl(RETURN_URL+"?flag=ali@"+order.getId()+"@");

        //包装一下结果, 塞入订单号
        Map<String, String> map = new HashMap<>();
        map.put("form", AliH5PayUtil.alipay(orderBean));
        map.put("orderId", order.getId());
        return new R<>(map);
    }

    //支付宝扫码支付
    @GetMapping("/aliCreateOrderNative")
    public R aliCreateOrderNative(Integer orgId, Integer goodsId){
        OnlineCourseGoodsEntity goods = goodsMapper.selectById(goodsId);
        //生成订单
        H5PayOrder order = new H5PayOrder();
        order.setOrgId(orgId);
        order.setPayMethod("支付宝扫码");
        order.setAmount(goods.getPrice());
        //购买的时长+赠送的时长为实际账号获得时长
        order.setDuration(goods.getBuyDuration() + goods.getGiveDuration());
        orderMapper.insert(order);

        AlipayClient alipayClient = new DefaultAlipayClient(config.URL, config.APPID,
		config.RSA_PRIVATE_KEY, config.FORMAT, config.CHARSET,
        config.ALIPAY_PUBLIC_KEY,config.SIGNTYPE);
        AlipayTradePrecreateRequest request = new AlipayTradePrecreateRequest();
        AlipayTradePrecreateModel model = new AlipayTradePrecreateModel();
        model.setOutTradeNo(order.getId());
		model.setTotalAmount(goods.getPrice().toString());
		model.setSubject(ORDER_BODY);
        request.setNotifyUrl(ALI_NOTIFY_URL);
        request.setBizModel(model);
        try {
            AlipayTradePrecreateResponse response = alipayClient.execute(request);
            Map<String, String> map = new HashMap<>();
            map.put("code_url", response.getQrCode());
            map.put("orderId", order.getId());
            return new R<>(map);
        }catch (Exception e) {
			e.printStackTrace();
			throw new BusinessException("支付宝处理异常！");
        }
    }

    @GetMapping("/aliQueryOrder")
    public R aliQueryOrder(String orderId) {
        AlipayClient alipayClient = new DefaultAlipayClient(config.URL, config.APPID,
		config.RSA_PRIVATE_KEY, config.FORMAT, config.CHARSET,
		config.ALIPAY_PUBLIC_KEY,config.SIGNTYPE);
        AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();
        AlipayTradeQueryModel model = new AlipayTradeQueryModel();
        model.setOutTradeNo(orderId);
        request.setBizModel(model);
        try {
            AlipayTradeQueryResponse response = alipayClient.execute(request);
            if(response.isSuccess()){
                if(response.getTradeStatus().equals("TRADE_SUCCESS")){
                    return new R<>(true);
                }else{
                    return new R<>(false);
                }       
            }else{
                return new R<>(false);
            }
		} catch (Exception e) {
			e.printStackTrace();
			throw new BusinessException("支付宝回调处理异常！");
        }
    }

    @PostMapping("/aliNotify")
    @Transactional(rollbackFor = Exception.class)
    public R aliNotify(HttpServletRequest request, AliReturnPayBean returnPay, HttpServletResponse response){
        H5PayOrder order = orderMapper.selectById(returnPay.getOut_trade_no());
        if(order.getStatus() == 0){
            order.setStatus(1);
            orderMapper.updateById(order);
            //更新在线课的课时
            Organization org = organMapper.selectById(order.getOrgId());
            //机构剩余课时数量为:原有数量+本次购买获取数量
            org.setOnlineCourseAvail(org.getOnlineCourseAvail() + order.getDuration());
            organMapper.updateById(org);
        }
        return new R<>(returnPay);
    }

    @GetMapping("/getTeacherList")
    public R getTeacherList(String orgId){
        return new R<>(goodsMapper.getTeacherList(orgId));
    }

    @GetMapping("/getSchedule")
    public R getSchedule(String teacherId, String date){
        return new R<>(goodsMapper.getSchedule(teacherId, date));
    }

    @GetMapping("/getMonthSchedule")
    public R getMonthSchedule(String teacherId, String month){
        return new R<>(goodsMapper.getMonthSchedule(teacherId, month));
    }
}